package gov.nasa.anml.lifted;

import java.util.ArrayList;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.PDDL.Argument;
import gov.nasa.anml.PDDL.BooleanExpression;
import gov.nasa.anml.PDDL.Effect;
import gov.nasa.anml.PDDL.FloatExpression;
import gov.nasa.anml.PDDL.Parameter;
import gov.nasa.anml.PDDL.Predicate;
import gov.nasa.anml.PDDL.Time;
import gov.nasa.anml.utility.*;

public class TimedExpression<T extends SimpleObject<? super T>> extends IntervalExpression<T> {

	public Expression<T,?> e;
	
	public TimedExpression() {
	}

	public boolean apply(State p, int contextID, State c) {
		// have to shift time before applying
		return false;
	}
	public TypeCode typeCode() {
		return e.typeCode();
	}
	public T value(State s) {
		T ret=null;
		if (false /* last time */) {
			ret = e.value(s);
		}
		while(ANMLBoolean.True.v == false /* scan history */) {
			if (ret.compareTo(e.value(s)) != 0)
				return null;
		}
		return e.value(s); // return ret;
	}

	

	// TODO 
	// FIXME 
	// all of the following
	public void translateDecl(PDDL pddl, Interval unit) {
		e.translateDecl(pddl,unit);
	}

	public PDDL.Expression translateExpr(PDDL pddl, Interval unit) {
		PDDL.Time part = PDDL.getPart(unit,this);
		if (part == null) {
			System.err.println("Haven't implemented non-PDDL time access (yet).");
			//unit.asPDDLAction().condition.arguments.add(pddl.FalseCondition);
			part = PDDL.Time.All; // might work?
		} else if (part == Time.Timeless) {
			part = PDDL.Time.All;
			System.err.println("A timeless timed expression? In Timed.translateExpr(), interpreting as All. " + e);
		}
		copyPDDL(unit);
		PDDL.Expression exp = e.translateExpr(pddl,this);
		if (e instanceof ConstantExpression<?>)
			return exp;
		switch(e.typeCode()) {
		case Boolean:
			PDDL.BooleanExpression b = (PDDL.BooleanExpression) exp;
			ArrayList<PDDL.BooleanExpression> a = new ArrayList<PDDL.BooleanExpression>();
			switch(part) {
			case Start:
			case End:
			case Interim:
				return pddl.wrap(part,b);
			case All:
				a.add(pddl.wrap(PDDL.Time.Start,b));
			case EndHalf:
				a.add(pddl.wrap(PDDL.Time.Interim,b));
				a.add(pddl.wrap(PDDL.Time.End,b));
				break;
			case StartHalf:
				a.add(pddl.wrap(PDDL.Time.Start,b));
				a.add(pddl.wrap(PDDL.Time.Interim,b));
				break;
			default:
				System.err.println("New PDDL.Time constant unaccounted for in TimedExpression.");
				return exp;
			}
			return pddl.wrap(PDDL.Op.and,a);
		case Float:
			FloatExpression f = (FloatExpression) exp;
			switch(part) {
			case Start:
			case End:
			case Interim:
				return pddl.wrap(part,f);
			case All:
			case StartHalf:
				return pddl.wrap(Time.Start,f);
			case EndHalf:
				return pddl.wrap(Time.Interim,f);
			default:
				System.err.println("New PDDL.Time constant unaccounted for in ConstantFunctionRef.");
				return exp;
			}
		default:
			System.err.println("Oops!");
			return exp;
		}
	}

	@Override
	public void translateStmt(PDDL pddl, Interval unit, PDDL.Time time) {
		PDDL.Time part = PDDL.getPart(unit,this);
		if (part == null) {
			System.err.println("Haven't implemented non-PDDL time access (yet).");
			part = PDDL.Time.All;
		} else if (part == Time.Timeless) {
			System.err.println("A timeless timed expression.  Intriguing.");
			part = PDDL.Time.All;
			System.err.println(e.toString());
		}
		copyPDDL(unit);
		if (e.typeCode() != TypeCode.Boolean) {
			System.err.println("Warning: Non-boolean expression-as-statement (i.e., a condition) found in: " + e.toString());
			getPDDLConditions().add(pddl.FalseCondition);
			return;
		}
		e.translateStmt(pddl, this, part);
	}
	
}
